﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Kaleida.ServiceMonitor.Model.Runtime;

namespace Kaleida.ServiceMonitor.UI
{
    class NotificationPanelFactory
    {
        internal static List<INotificationPanel> BuildPanels()
        {
            var searchAssemblies = new[] { Assembly.GetExecutingAssembly() };
            var types = GetNotificationPanelTypes(searchAssemblies);
            return types.Select(CreatePanel).ToList();
        }

        private static INotificationPanel CreatePanel(Type type)
        {
            try
            {
                return (INotificationPanel)Activator.CreateInstance(type);
            }
            catch (Exception e)
            {
                throw new InvalidOperationException(string.Format("Could not instantiate Notification Panel from Type '{0}': {1}", type.Name, e), e);
            }
        }

        private static IEnumerable<Type> GetNotificationPanelTypes(IEnumerable<Assembly> searchAssemblies)
        {
            
            var searchTypes = searchAssemblies.SelectMany(i => i.GetTypes()).ToList();

            var withCorrectBase = new HashSet<Type>(searchTypes.Where(i => i.DerivesFrom(typeof(INotificationPanel))));
            var withPublicVisibility = new HashSet<Type>(searchTypes.Where(i => i.IsVisible));
            var withPublicDefaultConstructor = new HashSet<Type>(searchTypes.Where(i => i.HasPublicDefaultConstructor()));

            return withCorrectBase.Intersect(withPublicVisibility).Intersect(withPublicDefaultConstructor).ToList();
        }

    }
}
